const fs = require("fs");
const sharp = require("sharp");
const grunt = require("grunt");
const {
  buildResponse,
  successFormat,
  errorFormat,
  gzip,
  common,
} = require("./common.js");
const readFile = (url) => {
  return new Promise((resolve, reject) => {
    fs.readFile(url, "binary", function (err, file) {
      if (err) {
        reject(err);
      } else {
        resolve(file);
      }
    });
  });
};
const readLocalFile = (fileName, app, req, res) => {
  readFile("./public/imgs/" + fileName[2] + ".webp")
    .then((file) => {
      console.log("[readFile]", "ok.");
      app.$redis
        .set(fileName[2], file)
        .then(() => {
          res.write(file, "binary");
          res.end();
        })
        .catch((err) => {
          console.error("[redis]", err);
          res.end(
            buildResponse(
              req,
              errorFormat(0, {
                err,
                message: "redis set error.",
              })
            )
          );
        });
    })
    .catch((err) => {
      res.end(
        buildResponse(
          req,
          errorFormat(0, {
            err,
            message: "readFile webp error.",
          })
        )
      );
    });
};
const toWebp = (app, req, res) => {
  console.log("[toWebp]", "start...");
  app.$request
    .fetchImage(req.query.url)
    .then((data) => {
      const newSharp = sharp(data.url, {
        animated: data.ext === "gif" ? true : false,
        //background: { alpha: 0 },
      });
      if (req.query && req.query.size) {
        const size = req.query.size.split(",");
        newSharp.resize(parseFloat(size[0]), parseFloat(size[1]), {
          fit: sharp.fit[(req.query && req.query.fit) || "contain"],
        });
      }
      //newSharp.webp({ quality: req.query.quality || 85 });
      newSharp.toFile("./public/imgs/" + data.name + ".webp", (err, info) => {
        console.error("[toWebp]", "[sharp.toFile]", err, info);
        if (err) {
          req.query.type !== "file"
            ? res.end(
                buildResponse(
                  req,
                  errorFormat(0, {
                    err,
                    message: "toFile Error.",
                  })
                )
              )
            : res.end({});
        } else {
          if (!req.query.type || req.query.type !== "file") {
            res.end(
              buildResponse(
                req,
                successFormat(200, {
                  err,
                  url: "/imgs/" + data.name + ".webp",
                })
              )
            );
          } else {
            readFile("./public/imgs/" + data.name + ".webp")
              .then((file) => {
                res.write(file, "binary");
                res.end();
              })
              .catch((err) => {
                res.end(
                  buildResponse(
                    req,
                    errorFormat(0, {
                      err,
                      message: "readFile webp error.",
                    })
                  )
                );
              });
          }
        }
      });
    })
    .catch((err) => {
      console.log("[toWebp]", "[fetchImage]", err);
      res.end(
        buildResponse(req, errorFormat(0, { err, message: "readFile error." }))
      );
    });
};
const defaultToWebpTask = (fileName, app, req, res) => {
  console.log("[defaultToWebpTask] start...");
  const isExists = grunt.file.exists("./public/imgs/" + fileName[2] + ".webp");
  console.log("[isExists]", isExists);
  if (isExists) {
    if (req.query.type && req.query.type === "file") {
      readLocalFile(fileName, app, req, res);
    } else {
      res.end(
        buildResponse(
          req,
          successFormat(200, {
            err: {},
            url: "/imgs/" + fileName[1] + ".webp",
          })
        )
      );
    }
  } else {
    toWebp(app, req, res);
  }
};

exports.done = function (app) {
  app
    .route("/toWebp")
    .all(function (req, res, next) {
      if (!req.query.type || req.query.type !== "file") {
        gzip(req, res);
        common(req, res);
      } else {
        res.header("Accept-Ranges", "bytes");
        res.header("Content-Type", "image/webp");
      }
      next();
    })
    .get(function (req, res, next) {
      if (req.query && req.query.url) {
        const fileName = /.+\/((.+)\.(png|jpg|jpeg|gif))$/.exec(req.query.url);
        if (!fileName) {
          res.end(
            buildResponse(
              req,
              errorFormat(0, { err, message: "Error parsing file name." })
            )
          );
          return;
        }
        app.$redis
          .get(fileName[2], true)
          .then((val) => {
            if (val) {
              res.write(val, "binary");
              res.end();
            } else {
              defaultToWebpTask(fileName, app, req, res);
            }
          })
          .catch((err) => {
            console.error("[redis]", err);
            defaultToWebpTask(fileName, app, req, res);
          });
      } else {
        res.end(buildResponse(req, errorFormat(0, {})));
      }
    });
};
